import logging
from typing import Dict

import cacheout
import requests
from common.utils.encrypt import RSAEncryptor
from web.common.error_code import ErrorCode


class AuthService:
    __cache = cacheout.Cache()
    ERROR_CODE_MAP: Dict[str, ErrorCode] = {

    }
    DEFAULT_ERROR_CODE = ErrorCode.AUTH_SERVER_ERROR

    def __init__(self):
        self.server_host = ''
        self._session = requests.session()
        self._auth_intranet_host = 'https://devblocktrade.yazhan.vip'
        self._rsa_public_key = ''

    def login(self, email, pwd, code_2fa, encrypt=True):
        pwd = RSAEncryptor.encrypt_data(self._rsa_public_key, pwd) if encrypt else pwd
        url = f'{self.server_host}/api/v1/auth/sign_in'
        return self._request(
            url,
            params={'email': email, 'password': pwd, 'code_2fa': code_2fa}
        )

    def update_pwd(self, token, old_pwd, pwd,code_2fa, encrypt=True):
        if encrypt:
            old_pwd = RSAEncryptor.encrypt_data(self._rsa_public_key, old_pwd)
            pwd = RSAEncryptor.encrypt_data(self._rsa_public_key, pwd)

        url = f'{self.server_host}/api/v1/auth/user/password/update'
        return self._request(
            url, headers={'Authorization': token},
            params={'old_password': old_pwd, 'password': pwd,'code_2fa':code_2fa}
        )

    def status_2fa(self,token):
        url = f'{self.server_host}/api/v1/security/status2FA'
        return self._request(url, headers={'Authorization': token})

    def enable_2fa(self, token, secret_2fa, code_2fa):
        url = f'{self.server_host}/api/v1/security/enable2FA'
        return self._request(url, headers={'Authorization': token}, params={"secret_2fa": code_2fa, "code_2fa": code_2fa})

    def disable_2fa(self,token,pwd,code_2fa,encrypt=True):
        if encrypt:
            pwd = RSAEncryptor.encrypt_data(self._rsa_public_key, pwd)
        url = f'{self.server_host}/api/v1/security/disable2FA'
        return self._request(url, headers={'Authorization': token}, params={"code_2fa": code_2fa, "password": pwd})

    def new_secret(self,token):
        url = f'{self.server_host}/api/v1/security/newSecret'
        return self._request(url, headers={'Authorization': token}, method='GET')

    def get_user_info(self, token):
        url = f'{self.server_host}/api/v1/auth/user/info'
        return self._request(url, headers={'Authorization': token}, method='GET')

    def logout(self, token):
        url = f'{self.server_host}/api/v1/auth/sign_out'
        return self._request(url, headers={'Authorization': token})

    def verify(self, token, pwd, code_2fa, encrypt=True):
        url = f'{self.server_host}/api/v1/auth/user/verify'
        pwd = RSAEncryptor.encrypt_data(self._rsa_public_key, pwd) if encrypt else pwd
        return self._request(
            url, headers={'Authorization': token}, params={'password': pwd, 'code_2fa': code_2fa}).json()

    def _request(self, url, params=None, headers=None, method='POST'):
        try:
            params = params or {}
            headers = headers or {}
            if method == 'GET':
                resp = self._session.get(url, headers=headers, params=params).json()
            else:
                resp = self._session.post(url, headers=headers, json=params).json()
            code = str(resp.get('code'))
            if code not in ('200', '0'):
                error_code = self.ERROR_CODE_MAP.get(code, self.DEFAULT_ERROR_CODE)
                logging.error(f'request auth service url {url} failed, params is {params}, resp is {resp}')
                raise error_code.to_error()
            return resp.get('data')
        except Exception as e:
            logging.exception(f'request auth {url} with {params} except: {e}')
            raise ErrorCode.AUTH_SERVER_ERROR.to_error()

    def get_kyc_info(self, token):
        url = f'{self.server_host}/api/v1/auth/user/kyc'
        headers = {'Authorization': token}
        return self._request(url, headers=headers)

    def get_user_kyc_info(self, user_id):
        url = f'{self._auth_intranet_host}/api/v1/admin/user/info'
        params = {'user_id': user_id}
        return self._request(url, params, )
